﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Xml.Serialization;
using System.Net.NetworkInformation;
using Phone.Framework.CaliburnExtensions.Results;
using Phone.Framework.Threads;

namespace Phone.Framework.Net
{
    /// <summary>
    /// 网络工具类。
    /// </summary>
    public abstract class WebUtils
    {
        //public static void DoPost(string url, IDictionary<string, string> parameters)
        //{
        //    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
        //    req.Method = "POST";
        //    byte[] postData = Encoding.UTF8.GetBytes(BuildPostData(parameters));

        //    IAsyncResult result = (IAsyncResult)req.BeginGetRequestStream(new AsyncCallback((IAsyncResult ar) =>
        //    {
        //        HttpWebRequest request = ar.AsyncState as HttpWebRequest;
        //        //request.ContentType = "application/atom+xml";
        //        Stream reqStream = request.EndGetRequestStream(ar);
        //        reqStream.Write(postData, 0, postData.Length);
        //        reqStream.Close();

        //        request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);

        //    }), req);
        //}

        ///// <summary>
        ///// 执行HTTP GET请求。
        ///// </summary>
        ///// <param name="url">请求地址</param>
        ///// <param name="parameters">请求参数</param>
        ///// <returns>HTTP响应</returns>
        //public static void DoGet(string url, IDictionary<string, string> parameters)
        //{
        //    DoGet(url, parameters, null);
        //}



        public static void DoTextGet(string url, IDictionary<string, string> parameters,
            Action<string> action)
        {
            DoGet<string>(url, parameters,DataType.Text,action);
        }

        public static void DoTextGet(string url, Action<string> action)
        {
            DoTextGet(url, null, action);
        }

        public static void DoJsonGet<T>(string url, Action<T> action)
        {
            DoGet<T>(url, null, DataType.JSON, action);
        }

        public static void DoXMLGet<T>(string url, Action<T> action)
        {
            DoGet<T>(url, null, DataType.XML, action);
        }

        public static void DoGet<T>(string url, IDictionary<string, string> parameters, Action<T> action)
        {
            DoGet<T>(url, parameters, DataType.JSON, action);
        }

        public static void DoGet<T>(string url, IDictionary<string, string> parameters,
            DataType dataType,
            Action<T> action)
        {
            DoGet<T>(url, parameters,dataType,action, null);
        }

        public static void DoGet<T>(string url, IDictionary<string, string> parameters,DataType dataType,
        Action<T> action,Action<Exception> error)
        {
            ResultHelper.Execute(LoadingResult.Default());
            if (!NetworkUtil.GetNetworkAvailable())
            {
                ResultHelper.Execute(new LoadedResult());
                if (error != null) error(new Exception("Network is not available"));
                return;
            }

            if (parameters != null && parameters.Count > 0)
            {
                if (url.Contains("?"))
                {
                    url = string.Format("{0}&{1}", url, BuildPostData(parameters));
                }
                else
                {
                    url = string.Format("{0}?{1}", url, BuildPostData(parameters));
                }
            }

            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
            req.Method = "GET";
            var data = new AsyncCallbackData<T>() { Request = req, Action = action, DataType = dataType };
            req.BeginGetResponse(new AsyncCallback(ResponseCallback<T>), data);
        }

        private static void ResponseCallback<T>(IAsyncResult ar)
        {
            var request = ar.AsyncState as AsyncCallbackData<T>;
            var response = request.Request.EndGetResponse(ar) as HttpWebResponse;

            T obj = default(T);
            if (request.DataType == DataType.Text)
                obj = (T)(GetResponseAsString(response) as Object);
            else if (request.DataType == DataType.JSON)
                obj = GetResponseAsObject<T>(response);
            else if (request.DataType == DataType.XML)
                obj = GetResponseAsObjectWithXML<T>(response);

            response.Close();
            UIThread.Invoke(() => {
                ResultHelper.Execute(new LoadedResult());
            });
           
            if (request.Action != null)
                request.Action(obj);
        }

        private static T GetResponseResult<T>(HttpWebResponse rsp, Encoding encoding, DataType dataType)
        {
            Stream stream = null;
            StreamReader reader = null;
            var obj = default(T);

            try
            {
                // 以字符流的方式读取HTTP响应
                stream = rsp.GetResponseStream();
                switch (dataType)
                {
                    case DataType.Text:
                        StringBuilder result = new StringBuilder();
                        reader = new StreamReader(stream, encoding);

                        // 每次读取不大于256个字符，并写入字符串
                        char[] buffer = new char[256];
                        int readBytes = 0;
                        while ((readBytes = reader.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            result.Append(buffer, 0, readBytes);
                        }
                        obj = (T)(result.ToString() as Object);
                        break;
                    case DataType.JSON:
                        DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(T));
                        var tempJsonObj = js.ReadObject(stream);
                        if (tempJsonObj != null)
                            obj = (T)tempJsonObj;
                        break;
                    case DataType.XML:
                        XmlSerializer xs = new XmlSerializer(typeof(T));
                        var temp = xs.Deserialize(stream);
                        if (temp != null)
                            obj = (T)temp;
                        break;
                    default:
                        break;
                }

            }
            finally
            {
                // 释放资源
                if (reader != null) reader.Close();
                if (stream != null) stream.Close();
                if (rsp != null) rsp.Close();
            }

            return obj;
        }

        private static string GetResponseAsString(HttpWebResponse rsp)
        {
            return GetResponseResult<string>(rsp, Encoding.UTF8, DataType.Text); ;
        }

        private static T GetResponseAsObjectWithXML<T>(HttpWebResponse rsp)
        {
            return GetResponseResult<T>(rsp, Encoding.UTF8, DataType.XML);
        }

        private static T GetResponseAsObject<T>(HttpWebResponse rsp)
        {
            return GetResponseResult<T>(rsp, Encoding.UTF8, DataType.JSON);
        }

        /// <summary>
        /// 组装普通文本请求参数。
        /// </summary>
        /// <param name="parameters">Key-Value形式请求参数字典</param>
        /// <returns>URL编码后的请求数据</returns>
        private static string BuildPostData(IDictionary<string, string> parameters)
        {
            StringBuilder postData = new StringBuilder();
            bool hasParam = false;

            IEnumerator<KeyValuePair<string, string>> dem = parameters.GetEnumerator();
            while (dem.MoveNext())
            {
                string name = dem.Current.Key;
                string value = dem.Current.Value;
                // 忽略参数名或参数值为空的参数
                if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
                {
                    if (hasParam)
                    {
                        postData.Append("&");
                    }

                    postData.Append(name);
                    postData.Append("=");
                    postData.Append(Uri.EscapeDataString(value));
                    hasParam = true;
                }
            }
            return postData.ToString();
        }
    }
}
